
package results;

import java.io.Serializable;
import utils.*;
import objects.SimObject;
import java.util.*;

import kernel.*;


/**
 * Used to monitor the network performance.
 * A probe monitors a particular value of a traceable object
 * At the current time, the stations only are considered
 * 
 * @author gael, guillaume
 * @created 27 febr. 2004
 */
public abstract class Probe implements Traceable, Serializable{
	
    // Constants for identifying the loop period
	
    /** Deplacement Loop period */
    public final static int DEPL_LOOP = 0;	// Deplacement
	
    /** Communication Loop period */
    public final static int COM_LOOP = 1;	// comunication

    public boolean _hasChanged;

    public boolean equals(Object o){
	if(o instanceof Probe){
	    return (((Probe)o).getPropertyName().equals(this.getPropertyName())
		    &&
		    ((Probe)o).getLinkedStation().equals(this.getLinkedStation()));
	}else{
	    return false;
	}
    }
	


    /**
     * it will depend how we want to implement the simulation time
     * if we consider the currentTime doesn't change in a loop period,
     * we could update this time and all the probes will refer to it.
     * If we update this time, each time we use getXML it has not no be
     * static.
     * We'll take a decision later
     */
    public static Double _currentTime;
	
    /**
     * Allows to generate a unique identifier per probe
     */
    private static int _probeNb = 0;
	
    /**
     * Indicate in which loop period we are
     * DEPL or COM
     */
    private int _whichLoopPeriod;
	
    /**
     * _currentValue is used in order to store the last value
     * monitored by the probe, used in order to know whether 
     * the value has changed since the last time  
     */
    private Object _lastValue;

    /**
     * date of the last record captured
     */
    private Double _lastRecordTime;

    private Double _loopTime;
	
    // indicates whether the value has changed since the last update
    // this indicator is updated by the method updateValue
    // private boolean _changed;
	
    // added 29/03/04
    /** 
     * _linkedStation indicates the station linked to this probe
     */
    protected Traceable _linkedStation;
	
    /**
     * Key identifying the probe in the xml file
     * It has not to change during the simulation
     * Can be get by the xmlKey method of the traceable object
     */
    protected final String _xmlKey;
	
    // No more needed as astually this property doesn't change
    // protected String _propertyName;
	
    protected String _probeName;

    // collection of Data measured by the probe
    protected HashMap<Double,Object> _data;
	
    /**
     * Constructor 
     * @param whichLoopPeriod specify in which loop of Result the probe will be added
     * @param t traceable object to monitor
     * @param propertyName property of the traceable object to monitor
     * @param probeName probe name
     */
    public Probe(int whichLoopPeriod, Traceable t,String probeName){
	_whichLoopPeriod=whichLoopPeriod;
	_linkedStation = t;
	_lastValue = null;
	_xmlKey = "probe_" + _probeNb++;
	_probeName = probeName;
	_data = new HashMap<Double,Object>();
	_lastRecordTime = -1.;
	_loopTime = -1.;
    }
	
 	
    /**
     * Indicates which property of the traceable object
     * the probe monitors
     * @return the property
     */
    public abstract String getPropertyName();

    /**
     * Get the descitption of the probe
     * @return probe description
     * @see Results.Probe#getProbeDescription()
     */
    public abstract String getProbeDescription();


    public String xmlId(){
	return "";
    }
	
    /**
     * Accessor to the current value monitored by the probe
     * It has to be redifined in each extended probe
     * @return a new Object which contains the value 
     */
    protected abstract Object getValue();
    public Object getBonoboValue()
    {
	return getValue();
    }

    public Traceable getLinkedStation(){
	return _linkedStation;
    }

    public void capture(){
	Object oldValue = _lastValue;
	_lastValue = getValue();
	_hasChanged = !(_lastValue.equals(oldValue));
	Double currentTime = getCurrentTime();

	if(_loopTime == -1.){
	    if(currentTime == 0){
		_loopTime = 1.;
	    }else{
		_loopTime = new Double(Simulator.getSimulator().frequency);
	    }
	}

	if(_hasChanged){
	    if(_lastRecordTime != _currentTime - _loopTime && oldValue != null && !oldValue.equals("")){
		_data.put(currentTime - _loopTime,oldValue);
	    }
	    if(_lastValue != null && !_lastValue.equals("")){
		_data.put(currentTime,_lastValue);
		setLastRecordTime(currentTime);
	    }
	}
    }
	
    public void captureLast(double lasttime){
	_data.put(lasttime,_lastValue);
    }

    /**
     * Accessor to the current value monitored by the probe
     * Has been done in order to improve performance : it is  
     * useless calculating a second time the value.
     * 
     * @precondition hasChanged have just been called
     * @return a new Object which contains the value 
     */
    protected Object getValueChanged(){
	return _lastValue;
    }
	
	
    /**
     * Indicate whether the value has changed 
     * Note : update the last value as well
     * @return whether it has changed since the last update
     */
    protected boolean hasChanged(){
	return _hasChanged;
    }
	
    /**
     * Get a unique xml representation for the probe
     * The representation is common except for the type
     * @return XML representation
     */ 
    public String xmlDump() {	
	HashMap<String,Object> attr = new HashMap<String,Object>();
	attr.put("name",_probeName);
	attr.put("uuid_ref",((SimObject)_linkedStation).getUUID());
	attr.put("property",getPropertyName());
	attr.put("loop",_whichLoopPeriod);
	attr.put("type",this.getClass().getName());

	String s = XMLHelper.XMLCompleteTag("probe",attr);
	return s;
    }
	
    /**
     * Get a xml trace of captured measures
     * @return trace associated with the probe
     */ 
    protected String xmlTrace(){
	String s = new String();
	HashMap<String,Object> attr = new HashMap<String,Object>();
	attr.put("uuid_ref",((SimObject)_linkedStation).getUUID());
	attr.put("property",getPropertyName());

	s = XMLHelper.XMLOpenTag("probe_result",attr);

	Set<Double> keys = _data.keySet();
	TreeSet<Double> orderedKeys = new TreeSet(keys);
	for(Double d : orderedKeys){
	    // not using XMLHlper.XMLCompleteTag in order to reduce indirections
	    s += "<data time=\"" + d + "\" value=\"" + _data.get(d) + "\" />\n";
   	}

	s += XMLHelper.XMLCloseTag("probe_result");
	return s;
    }
	
    public void testClassName(){
	System.out.println(this.getClass().getName());
    }

    /**
     * Get the loop period
     * @return loop period in which the loop iterates 
     */
    protected int getLoopPeriod(){
	return _whichLoopPeriod;
    }
	
    protected static Double getCurrentTime(){
	return _currentTime;
    }
    
    protected static void setCurrentTime(Double currentTime){
	_currentTime = currentTime;
    }

    public Double getLastRecordTime(){
	return _lastRecordTime;
    }

    public void setLastRecordTime(Double time){
	_lastRecordTime = new Double(time);
    }
}


